home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-04 / nasanets.zip / NET.C < prev    next >
C/C++ Source or Header  |  1990-06-07  |  23KB  |  569 lines

  1. /*=============================*/
  2. /*           NETS              */
  3. /*                             */
  4. /* a product of the AI Section */
  5. /* NASA, Johnson Space Center  */
  6. /*                             */
  7. /* principal author:           */
  8. /*       Paul Baffes           */
  9. /*                             */
  10. /* contributing authors:       */
  11. /*      Bryan Dulock           */
  12. /*      Chris Ortiz            */
  13. /*=============================*/
  14.  
  15.  
  16. /*
  17. ----------------------------------------------------------------------
  18.   Code For Manipulation Of Net Structures (Prefix = N_)
  19. ----------------------------------------------------------------------
  20.   This code is divided into 3 major sections:
  21.  
  22.   (1) include files
  23.   (2) externed functions 
  24.   (3) subroutines
  25.  
  26.   Each section is further explained below.
  27. ----------------------------------------------------------------------
  28. */
  29.  
  30.  
  31. /*
  32. ----------------------------------------------------------------------
  33.   INCLUDE FILES
  34. ----------------------------------------------------------------------
  35. */
  36. #include  "common.h"
  37. #include  "weights.h"
  38. #include  "layer.h"
  39. #include  "net.h"
  40. #include  "netio.h"
  41.  
  42.  
  43. /*
  44. ----------------------------------------------------------------------
  45.   EXTERNED FUNCTIONS AND GLOBALS
  46. ----------------------------------------------------------------------
  47.   Below are the functions defined in other files which are used by the
  48.   code here. They are organized by section.
  49. ----------------------------------------------------------------------
  50. */
  51. extern  void         P_prop_input();
  52. extern  float        IO_my_get_float();
  53. extern  int          PS_get_float_from_file();
  54. extern  int          PS_skip_tokens();
  55. extern  Sint         C_float_to_Sint();
  56. extern  float        C_Sint_to_float();
  57. extern  char         *sys_alloc();
  58. extern  void         IO_print();
  59. extern  void         IO_reset_more();
  60. extern  int          IO_more();
  61. extern  void         IO_insert_format();
  62.  
  63. extern  FILE         *PA_open_binary();
  64. extern  void         PA_write_signature();
  65. extern  int          PA_check_signature();
  66. extern  int          PA_get_from_workfile();
  67. extern  int          PA_put_to_workfile();
  68. extern  void         PA_flush();
  69. extern    void         PA_put_ascii_wts();
  70. extern  Sint         PA_get_ascii_wts();
  71.  
  72. extern  char         IO_str[MAX_LINE_SIZE];
  73. extern char          IO_wkstr[MAX_LINE_SIZE];
  74.  
  75.  
  76. /*
  77. ======================================================================
  78.   ROUTINES IN NET.C                                                   
  79. ======================================================================
  80.   The routines in this file are grouped below by function.  Each routine
  81.   is prefixed by the string "N_" indicating that it is defined in the 
  82.   "net.c" file.  The types returned by the routines are also shown here
  83.   so that cross checking is more easily done between these functions
  84.   and the other files which intern them.
  85.  
  86.  
  87.   Type Returned                 Routine                                 
  88.   -------------                 -------                                 
  89.     Layer *                     N_get_layer
  90.     void                        N_query_net
  91.     int                         N_propagate_and_print
  92.     int                         N_reset_wts                    
  93.     void                        N_save_wts    
  94. ======================================================================
  95. */
  96.  
  97.  
  98. Layer  *N_get_layer(ptr_net, source)
  99. Net    *ptr_net;
  100. int    source;
  101. /*
  102. ----------------------------------------------------------------------
  103.  This routine searches through the list of layers associated with a   
  104.   net (pointed to by 'ptr_net') and returns a pointer to the layer    
  105.   with an ID equal to the 'source' number passed in.  If no such layer
  106.   is found, then an 'error layer' is returned; ie, a new layer is     
  107.   created with an ID = -1 (see the net.h file).                       
  108. ----------------------------------------------------------------------
  109. */
  110. BEGIN
  111.    Layer_lst  *next_layer;
  112.    Layer      *dummy;
  113.  
  114.    if (ptr_net->input_layer->ID == source)
  115.       return(ptr_net->input_layer);
  116.  
  117.    if (ptr_net->output_layer->ID == source)
  118.       return(ptr_net->output_layer);
  119.  
  120.    next_layer = ptr_net->hidden_front;
  121.    while (next_layer != NULL) BEGIN
  122.       if (next_layer->value->ID == source)
  123.          return(next_layer->value);
  124.       next_layer = next_layer->next;
  125.    ENDWHILE  
  126.  
  127.    dummy = (Layer *) sys_alloc((unsigned)sizeof(Layer));
  128.    dummy->ID = ERROR;
  129.    return(dummy);
  130.  
  131. END /* N_get_layer */
  132.  
  133.  
  134. void  N_query_net(ptr_net, in_file, out_fp, num_props)
  135. Net   *ptr_net;
  136. char  *in_file;
  137. FILE  *out_fp;
  138. int   num_props;
  139. /*
  140. ----------------------------------------------------------------------
  141.  This routine is used for passing input to the net to see what sort of
  142.   output comes out.  In other words, once you have taught a net you   
  143.   probably want to give it inputs and have outputs returned.  This    
  144.   routine takes care of that.
  145.   
  146.  Most of the work for this routine has already been coded.  All that  
  147.   needs to be done is to read in the inputs that the user wants tested
  148.   and then propagate them through the net.  Then the outputs are      
  149.   printed to the screen or a file, depending on the users input.
  150.   
  151.  The input for propagation can come either from the screen or a file,
  152.   and the same is true of the output. If the in_file is empty, then the
  153.   user is prompted from the screen. If the output file POINTER is NULL
  154.   the output goes to the screen.
  155.  
  156.  NOTE if "num_props" comes in as -1, this means the routine should 
  157.   propagate all the inputs it can find in the file. Otherwise, the
  158.   routine should propagate num_props number of inputs.
  159. ----------------------------------------------------------------------
  160. */
  161. BEGIN
  162.    int    i;
  163.    int    count, N_propagate_and_print();
  164.    float  tf1;
  165.    FILE   *fp;
  166.    
  167.    /*-----------------------------------------------*/
  168.    /* first reset the more function before printing */
  169.    /*-----------------------------------------------*/
  170.    IO_reset_more();
  171.  
  172.    /*-------------------------------------------*/
  173.    /* input from the screen if in_file is empty */
  174.    /*-------------------------------------------*/
  175.    if (in_file[0] == ENDSTRING) BEGIN
  176.       for (i = 0; i < ptr_net->input_layer->num_nodes; i++) BEGIN
  177.          sprintf(IO_str, "\n   Enter input for node %d: ", i);
  178.          IO_more(0);
  179.          tf1 = IO_my_get_float();
  180.          ptr_net->input_layer->node_outputs[i] = C_float_to_Sint(tf1);
  181.       ENDFOR
  182.       N_propagate_and_print(ptr_net, out_fp, 1);
  183.    ENDIF
  184.      
  185.    /*------------------------------------*/
  186.    /* Otherwise, get input from the file */
  187.    /*------------------------------------*/
  188.    else BEGIN
  189.    
  190.       /*---------------------------------------*/
  191.       /* open file; quit if it can't be opened */
  192.       /*---------------------------------------*/
  193.       if((fp = fopen(in_file, "rt")) == NULL) BEGIN
  194.          sprintf(IO_str, "\n*** can't open file %s for propagation ***\n", in_file);
  195.          IO_more(0);
  196.          return;
  197.       ENDIF
  198.       
  199.       /*-----------------------------------*/
  200.       /* next, loop for as many pairs as   */
  201.       /* the user specified in "num_props" */
  202.       /*-----------------------------------*/
  203.       count = 1;
  204.       while (PS_skip_tokens(fp, "(") == OK) BEGIN
  205.          /*-------------------------------------------*/
  206.          /* if past number of props, quit propagating */
  207.          /*-------------------------------------------*/
  208.          if (num_props >= 0)
  209.             if (count > num_props) break;
  210.          
  211.          /*--------------------------*/
  212.          /* Read inputs from in_file */
  213.          /*--------------------------*/
  214.          for (i = 0; i < ptr_net->input_layer->num_nodes; i++) BEGIN
  215.             if (PS_get_float_from_file(fp, &tf1) == OK) 
  216.                ptr_net->input_layer->node_outputs[i] = C_float_to_Sint(tf1);
  217.                   
  218.             /*-----------------------------------*/
  219.             /* quit if not enough inputs in file */
  220.             /*-----------------------------------*/
  221.             else BEGIN
  222.                sprintf(IO_str, "\n*** error: input %d too short ***\n",
  223.                        count);
  224.                IO_more(0);
  225.                return;
  226.             ENDELSE
  227.          ENDFOR
  228.          
  229.          if (N_propagate_and_print(ptr_net, out_fp, count) == ERROR) return;
  230.          count++;
  231.       ENDWHILE
  232.       
  233.       /*----------------------*/
  234.       /* close file when done */
  235.       /*----------------------*/
  236.       fclose(fp);
  237.    ENDELSE
  238.    
  239. END /* N_query_net */
  240.  
  241.  
  242. int  N_propagate_and_print(ptr_net, out_fp, input_num)
  243. Net   *ptr_net;
  244. FILE  *out_fp;
  245. int   input_num;
  246. /*
  247. ----------------------------------------------------------------------
  248.  This routine is used for passing input to the net to see what sort of
  249.   output comes out.  In other words, once you have taught a net you   
  250.   probably want to give it inputs and have outputs returned.  This    
  251.   routine takes care of that.   The inputs are passed to this function
  252.   by the pointer ptr_net.   The inputs are propagated through the network
  253.   and displayed at the terminal or written to a file depending of out_fp.
  254.   The "input_num" indicates the number of the input being processed 
  255.   which is used as part of the output.
  256.  NOTE that this guy assumes the inputs have been properly setup on the
  257.   input layer of the network BEFORE this routine is called.
  258. ---------------------------------------------------------------------
  259. */
  260. BEGIN
  261.    int    i, num_outs;
  262.    float  tf1;
  263.  
  264.    /*---------------------*/
  265.    /* propagate the input */
  266.    /*---------------------*/
  267.    P_prop_input(ptr_net);
  268.  
  269.    /*--------------------------------------------*/
  270.    /* send output to screen if out_fp is == NULL */
  271.    /*--------------------------------------------*/
  272.    if (out_fp == NULL) BEGIN
  273.       sprintf(IO_str, "\n\nThe Outputs for Input %d are:\n", input_num);
  274.       if (IO_more(0) == ERROR) 
  275.          return(ERROR);
  276.       for (i = 0; i < ptr_net->output_layer->num_nodes; i++) BEGIN
  277.          tf1 = C_Sint_to_float(ptr_net->output_layer->node_outputs[i]);
  278.          sprintf(IO_wkstr, "   for node %d the value %%.f\n", i);
  279.          IO_insert_format(IO_wkstr);
  280.          sprintf(IO_str, IO_wkstr, tf1);
  281.          if (IO_more(0) == ERROR) 
  282.             return(ERROR);
  283.       ENDFOR
  284.    ENDIF
  285.       
  286.    /*--------------------------------------------*/
  287.    /* otherwise, try to open the output file and */
  288.    /* write out the results of the propagation   */
  289.    /*--------------------------------------------*/
  290.    else BEGIN
  291.       num_outs = ptr_net->output_layer->num_nodes;
  292.       fprintf(out_fp, "\nOutputs for Input %d:\n(", input_num);
  293.       for (i = 0; i < num_outs; i++) BEGIN
  294.          tf1 = C_Sint_to_float(ptr_net->output_layer->node_outputs[i]);
  295.          sprintf(IO_wkstr, "%%.f%c", ((i%6 == 5) || (i==num_outs-1) ? '\n' : ' ') );
  296.          IO_insert_format(IO_wkstr);
  297.          fprintf( out_fp, IO_wkstr, tf1);  
  298.       ENDFOR
  299.       fprintf(out_fp, ")\n");
  300.    ENDELSE
  301.    return(OK);
  302.  
  303. END /* N_propagate_and_print */
  304.  
  305.  
  306. int  N_reset_wts(ptr_net, file_name, format)
  307. Net   *ptr_net;
  308. char  file_name[];
  309. int   format;
  310. /*
  311. ----------------------------------------------------------------------
  312.  This routine resets the weights of a net using a file specified by   
  313.   the user.  The idea is to move through the hidden layers list from  
  314.   the front, reading in values for all the incoming weights to a layer
  315.   Note that both the incoming and outgoing weight values do not need  
  316.   to be read in since the outgoing weights of one layer are the same  
  317.   as the incoming weights of the target layer.  Note also that the    
  318.   order of the movement through the hidden layers list is significant.
  319.   By starting at the front we skip over the input layer, thus we must 
  320.   use INCOMING weights, otherwise we would never set the weights      
  321.   coming OUT of layer 0!  Of course, we don't have to worry about any 
  322.   weights coming out of layer 1 (the output) because the output layer 
  323.   is defined as having no outgoing weights.      
  324.  A new addition to this routine (8-16-89) checks to see if the file 
  325.   has a "signature" which matches the format desired by the user. This
  326.   is done using the BIN_SIG (see common.h file) which is a hexidecimal
  327.   code written to a binary file (ie FAST_FORMAT file) at the very top.
  328.   If this signature is not present, the file is assumed to be PORTABLE_
  329.   FORMAT. If the presence/lack of the signature does not match with 
  330.   the desired format, then an error is returned (see PA_check_signature).                     
  331. ----------------------------------------------------------------------
  332. */
  333. BEGIN
  334.    Weights_lst  *cur_weight;
  335.    Layer_lst    *cur_layer;
  336.    Sint         *wt_values, tmp_Sint, *bias_values;
  337.    int          STATUS, flag, s_size, t_size, j;
  338.    int32        num_weights, i;
  339.    FILE         *fp;
  340.    
  341.    /*---------------------------------------------*/
  342.    /* check that the file format matches "format" */
  343.    /*---------------------------------------------*/
  344.    if (PA_check_signature(file_name, format) == ERROR)
  345.       return(ERROR);
  346.       
  347.    if (format == PORTABLE_FORMAT)
  348.       fp = fopen(file_name, "rt");
  349.    else
  350.       fp = PA_open_binary(file_name, READ_MODE);
  351.       
  352.    if (fp == NULL) BEGIN
  353.       sprintf(IO_str, "\n*** error, file %s cannot be opened ***\n", file_name);
  354.       IO_print(0);
  355.       STATUS = ERROR;
  356.    ENDIF
  357.    else BEGIN
  358.       /*-------------------------------------------------*/
  359.       /* once the file is open, init the value of STATUS */
  360.       /* and if a bin file, throw away the first 2-bytes */
  361.       /* since it will be the binary signature value     */
  362.       /*-------------------------------------------------*/
  363.       STATUS = OK;
  364.       if (format == FAST_FORMAT)
  365.          fread((char *)(&tmp_Sint), SIG_SIZE, 1, fp);
  366.  
  367.       cur_layer = ptr_net->hidden_front;
  368.       while ((cur_layer != NULL) && (STATUS == OK)) BEGIN /* for each layer */
  369.          /*--------------------------------------*/
  370.          /* then read in weight values for layer */
  371.          /*--------------------------------------*/
  372.          cur_weight = cur_layer->value->in_weights;
  373.          while ((cur_weight != NULL) && (STATUS == OK)) BEGIN
  374.             wt_values = cur_weight->value->values;
  375.             s_size    = cur_weight->value->source_size;
  376.             t_size    = cur_weight->value->target_size;
  377.             if (cur_weight->value->type == CONNECT_ALL)
  378.                num_weights = ((int32) s_size) * ((int32) t_size);
  379.             else if (s_size < t_size)
  380.                num_weights = ((int32) s_size) * ((int32) cur_weight->value->map_area);
  381.             else
  382.                num_weights = ((int32) t_size) * ((int32) cur_weight->value->map_area);
  383.             for (i = 0; i < num_weights; i++) BEGIN
  384.                /*--------------------------------------------*/
  385.                /* read in the next Sint from the appropriate */
  386.                /* file, depending upon the reading format    */
  387.                /*--------------------------------------------*/
  388.                if ( format == PORTABLE_FORMAT )
  389.                   flag = PA_get_ascii_wts(fp, &tmp_Sint);
  390.                else
  391.                   flag = PA_get_from_workfile(fp, &tmp_Sint);
  392.                
  393.                /*-------------------------------------*/
  394.                /* if everything went well, keep going */
  395.                /*-------------------------------------*/
  396.                if (flag == OK)
  397.                   wt_values[i] = tmp_Sint;
  398.                else BEGIN
  399.                   STATUS = ERROR;
  400.                   break;                 /* break out of 'for' loop */
  401.                ENDELSE
  402.             ENDFOR                  
  403.             cur_weight = cur_weight->next;
  404.          ENDWHILE
  405.          cur_layer = cur_layer->next;
  406.       ENDWHILE
  407.       
  408.       /*--------------------------------------------*/
  409.       /* if not enough values for weights then quit */
  410.       /*--------------------------------------------*/
  411.       if (STATUS == ERROR) BEGIN
  412.          sprintf(IO_str, "\n*** Not enough values to reset all weights ***\n");
  413.          IO_print(0);
  414.       ENDIF
  415.       /*--------------------------------*/
  416.       /* otherwise, get the bias values */
  417.       /*--------------------------------*/
  418.       else BEGIN
  419.          STATUS = OK;
  420.          cur_layer = ptr_net->hidden_front;
  421.          while ((cur_layer != NULL) && (STATUS == OK)) BEGIN /* for each layer */
  422.             /*-------------------------------*/
  423.             /* read in bias values for layer */
  424.             /*-------------------------------*/
  425.             bias_values = cur_layer->value->node_bias;
  426.             for (j = 0; j < cur_layer->value->num_nodes; j++) BEGIN
  427.                if (format == PORTABLE_FORMAT)
  428.                   flag = PA_get_ascii_wts(fp, &tmp_Sint);
  429.                else
  430.                   flag = PA_get_from_workfile(fp, &tmp_Sint);
  431.                if (flag == OK)
  432.                   bias_values[j] = tmp_Sint;
  433.                else BEGIN
  434.                   STATUS = ERROR;
  435.                   break;                 /* break out of 'for' loop */
  436.                ENDELSE
  437.             ENDFOR   
  438.          cur_layer = cur_layer->next;
  439.          ENDWHILE
  440.       ENDELSE
  441.       
  442.       if (STATUS == ERROR) BEGIN
  443.          sprintf(IO_str, "\n*** Not enough values to reset all biases ***\n");
  444.          IO_print(0);
  445.       ENDIF
  446.       fclose(fp);
  447.    ENDELSE
  448.    return(STATUS);
  449.  
  450. END /* N_reset_wts */
  451.  
  452.  
  453. void  N_save_wts(ptr_net, file_name, format)
  454. Net   *ptr_net;
  455. char  file_name[];
  456. int   format;
  457. /*
  458. ----------------------------------------------------------------------
  459.  This routine is identical to the one above, except for the error     
  460.   messages and the fact that the weights are being saved and not re-  
  461.   stored.  Note that a call to 'PA_flush' is made here.  That is done 
  462.   to make sure that the contents of the buffer are emptied to the     
  463.   output file.                                                         
  464. ----------------------------------------------------------------------
  465. */
  466. BEGIN
  467.    Weights_lst  *cur_weight;
  468.    Layer_lst    *cur_layer;
  469.    Sint         *wt_values, *bias_values;
  470.    int          STATUS, j, s_size, t_size;
  471.    int32        num_weights, i;
  472.    FILE         *fp;
  473.  
  474.    if (format == PORTABLE_FORMAT)
  475.       fp = fopen(file_name, "wt");
  476.    else
  477.       fp = PA_open_binary(file_name, WRITE_MODE);
  478.    
  479.    if ( fp == NULL ) BEGIN
  480.       sprintf(IO_str, "\n*** error, file %s cannot be opened ***\n", file_name);
  481.       IO_print(0);
  482.    ENDIF
  483.    else BEGIN
  484.       /*-----------------------------------------------*/
  485.       /* once the file is open, set the status flag to */
  486.       /* OK and output the binsignature if bin file    */
  487.       /*-----------------------------------------------*/
  488.       STATUS = OK;
  489.       if (format == FAST_FORMAT)
  490.          PA_write_signature(fp, BIN_SIG);
  491.  
  492.       cur_layer = ptr_net->hidden_front;
  493.       while ((cur_layer != NULL) && (STATUS == OK)) BEGIN
  494.          /*-----------------------------*/
  495.          /* write out weights for layer */
  496.          /*-----------------------------*/
  497.          cur_weight = cur_layer->value->in_weights;
  498.          while ((cur_weight != NULL) && (STATUS == OK)) BEGIN
  499.             wt_values = cur_weight->value->values;
  500.             s_size    = cur_weight->value->source_size;
  501.             t_size    = cur_weight->value->target_size;
  502.             if (cur_weight->value->type == CONNECT_ALL)
  503.                num_weights = ((int32) s_size) * ((int32) t_size);
  504.             else if (s_size < t_size)
  505.                num_weights = ((int32)s_size) * ((int32)cur_weight->value->map_area);
  506.             else
  507.                num_weights = ((int32)t_size) * ((int32)cur_weight->value->map_area);
  508.                
  509.             /*------------------------------------------------*/
  510.             /* after setting up, either print out as ascii or */
  511.             /* as binary, depending on the value of "format"  */
  512.             /*------------------------------------------------*/
  513.             if (format == PORTABLE_FORMAT)
  514.                 PA_put_ascii_wts(wt_values, num_weights, fp);
  515.             else
  516.                for (i = 0; i < num_weights; i++)
  517.                   if ((PA_put_to_workfile(fp, wt_values[i])) == ERROR) BEGIN 
  518.                      STATUS = ERROR;
  519.                      break;  /* break out of 'for' loop */
  520.                   ENDIF
  521.             cur_weight = cur_weight->next;
  522.          ENDWHILE
  523.          cur_layer = cur_layer->next;
  524.       ENDWHILE
  525.       
  526.       /*----------------------------------------*/
  527.       /* if error writing out weights then quit */
  528.       /*----------------------------------------*/
  529.       if (STATUS == ERROR) BEGIN
  530.          sprintf(IO_str, "\n*** error, not all weights were written ***\n");
  531.          IO_print(0);
  532.       ENDIF
  533.       /*--------------------------------------*/
  534.       /* otherwise, write out the bias values */
  535.       /*--------------------------------------*/
  536.       else BEGIN   
  537.          STATUS = OK;
  538.          cur_layer = ptr_net->hidden_front;
  539.          while ((cur_layer != NULL) && (STATUS == OK)) BEGIN
  540.             /*---------------------------------*/
  541.             /* write out bias values for layer */
  542.             /*---------------------------------*/
  543.             bias_values = cur_layer->value->node_bias;
  544.             if ( format == PORTABLE_FORMAT )
  545.                 PA_put_ascii_wts(bias_values, (int32)cur_layer->value->num_nodes, fp);
  546.             else
  547.                for (j = 0; j < cur_layer->value->num_nodes; j++)
  548.                   if ((PA_put_to_workfile(fp, bias_values[j])) == ERROR) BEGIN 
  549.                      STATUS = ERROR;
  550.                      break;  /* break out of 'for' loop */
  551.                   ENDIF
  552.             cur_layer = cur_layer->next;
  553.          ENDWHILE
  554.       ENDELSE /* loop for biases */
  555.       
  556.       /*---------------------------------------*/
  557.       /* check again for error before flushing */
  558.       /* the file and quitting the routine     */
  559.       /*---------------------------------------*/
  560.       if (STATUS == ERROR) BEGIN
  561.          sprintf(IO_str, "\n*** error, not all biases were written ***\n");
  562.          IO_print(0);
  563.       ENDIF
  564.       if ( format == FAST_FORMAT ) PA_flush(fp);
  565.       fclose(fp);
  566.    ENDELSE
  567.  
  568. END /* N_save_wts */
  569.